1

定义

保证一个类仅有以一个实例,仅能被实例化/创建一次,并提供全局的访问点。

单例模式是一种重要的设计模式,有些对象我们只需要创建一个,比如浏览器的window对象,模态对话框。实现这种设计模式其实很简单,最重要的是在创建实例的时候,用一个标记变量判断实例是否已经创建。

普通青年写法

function Singleton(name){
    this.name = name;
    this.instance = null;
}
Singleton.prototype.getName = function(){
    console.log('name: ' + this.name);
    return this.name;
}
Singleton.getInstance = function(name){
    if(!this.instance){
        this.instance = new Singleton(name);
    }
    return this.instance;
}
var a = Singleton.getInstance('a');
var b = Singleton.getInstance('b');
alert(a === b);

点评:
该写法不透明,使用者必须知道用Singleton.getInstance获取单例,而非通过更加通用的方法new xxx方式。

老司机写法

var CreateDiv = function(html){
    this.html = html;
    this.init();
}
CreateDiv.prototype.init = function(){
    var div = document.createElement('div');
    div.innerHTML = this.html;
    document.body.appendChild(div);
}
var SingletonDiv = (function(){
    var instance;
    return function(html){
        if(!instance){
            instance = new CreateDiv(html);
        }
        return instance;
    }
})()
var a = SingletonDiv('yyh');
var b = SingletonDiv('yyh1');

点评:
使用代理类+普通的类,使得职责分明。普通类负责实现基本功能,代理类管理单例。CreateDiv可以直接生产一个实例,而加上代理,可以实现单例。有木有一种模块拼凑的快感,这就实现了低耦合。

华丽丽的ES6

在ES6中,可以使用static方法代替闭包存储单例。

静态方法的单例模式

class Singleton {
    constructor(name) {
        this.name = name;
    }
    static getInstance(name) {
        if(!Singleton.instance) {
            Singleton.instance = new Singleton(name)
        }
        return Singleton.instance;
    }
    getName() {
        return this.name;
    }
}
const singletonA = Singleton.getInstance('yyh1');
const singletonB = Singleton.getInstance('yyh2');
console.log(singletonA === singletonB);
console.log(singletonA.getName() === singletonB.getName());

点评:ES6的静态方法,和闭包一样能在减少全局变量污染的同时,使标记变量更加长久的保存在内存中不被回收。

老司机的新技能(更加通用的实现方式)

// 负责创建DIV的基本功能
class CreateDiv {
    constructor(html) {
        this.html = html;
        this.init();
    }
    init() {
        const div = document.createElement('div');
        div.innerHTML = this.html;
        document.body.appendChild(div);
    }
}
// 负责管理单例
class ProxysingletonCreateDiv {
    constructor(htmlStr) {
        return ProxysingletonCreateDiv.getInstance(htmlStr);
    }
    static getInstance(name) {
        if(!ProxysingletonCreateDiv.instance) {
            ProxysingletonCreateDiv.instance = new CreateDiv(name)
        }
        return ProxysingletonCreateDiv.instance;
    }
}
const singletonC = new ProxysingletonCreateDiv('yyh1');
const singletonD = new ProxysingletonCreateDiv('yyh2');
console.log(singletonC === singletonD);
singletonC.init();
singletonD.init();

yyh1945
40 声望1 粉丝